package com.exsun.gateway.jt809.codec.protocol;


import exsun.jt808.data.config.jt809.Jt809MsgIdConfig;
import exsun.jt808.data.jt809_data.BasicVehicleInfo;
import exsun.jt808.data.jt809_data.alarm.main.UpWarnMsgAdptInfo;
import exsun.jt808.data.jt809_data.alarm.main.UpWarnMsgInfoEX;
import exsun.jt808.data.jt809_data.alarm.main.UpWarnMsgOperationInfoEx;
import exsun.jt808.data.jt809_data.alarm.main.UpWarnMsgUrgeTodoAck;
import exsun.jt808.data.jt809_data.linkmanage.*;
import exsun.jt808.data.jt809_data.monitor.main.*;
import exsun.jt808.data.jt809_data.platform.main.UpPlatformMsgInfoAck;
import exsun.jt808.data.jt809_data.platform.main.UpPlatformMsgPostQueryAck;
import exsun.jt808.data.jt809_data.vehicledynamic.GnssData;
import exsun.jt808.data.jt809_data.vehicledynamic.main.*;
import exsun.jt808.data.jt809_data.vehiclestatic.main.UpBaseMsgVehicleAddedAck;
import exsun.jt808.data.jt809_data.video.main.*;
import exsun.jt808.data.upload_data.jsatl12.AlarmAttachmentInfo;
import exsun.jt808.data.util.parse.BCD8421Operater;
import exsun.jt808.data.util.parse.BitOperator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 消息组包
 */
@Service
public class Jt809Encode {

    public byte[] nullRequestBody = new byte[0];
    public byte[] nullResponseBody = new byte[0];

    /**
     * 平台唯一编号
     */
    @Value("${platformInfo.platformId}")
    private String platformId;

    /**
     * 作为客户端的请求消息------------------------------------------------------
     */

    /**
     * 主链路登录请求消息
     *
     * @param upConnectReq
     * @return
     */
    public byte[] upConnectReq(UpConnectReq upConnectReq) {
        byte[] result = BitOperator.integerTo4Bytes(upConnectReq.getPlatFormId());
        result = BitOperator.concatAll(result,
                BitOperator.stringToBytes(upConnectReq.getPassword()),
                BitOperator.padRight(BitOperator.stringToBytes(upConnectReq.getDownLinkIp()),32),
                BitOperator.integerTo2Bytes(upConnectReq.getDownLinkPort()));
        return result;
    }

    public byte[] upConnectRsp(UpConnectRsp upConnectRsp){
        byte[] result =BitOperator.concatAll(BitOperator.integerTo1Bytes(upConnectRsp.getResult()),
                BitOperator.integerTo4Bytes(upConnectRsp.getCheckCode()));
        return result;
    }

    /**
     * 主链路注销请求消息组包
     *
     * @param upDisconnectReq
     * @return
     */
    public byte[] upDisconnectReq(UpDisconnectReq upDisconnectReq) {
        byte[] result;
        result = BitOperator.integerTo4Bytes(upDisconnectReq.getPlatFormId());
        result = BitOperator.concatAll(result,
                BitOperator.stringToBytes(upDisconnectReq.getPassword()));
        return result;
    }

    /**
     * 主链路连接保持请求消息组包
     *
     * @return
     */
    public byte[] upLinkTestReq() {
        return nullRequestBody;
    }

    /**
     * 主链路断开通知消息
     *
     * @param upDisconnectInform
     * @return
     */
    public byte[] upDisconnectInform(UpDisconnectInform upDisconnectInform) {
        byte[] result;
        result = BitOperator.integerTo1Bytes(upDisconnectInform.getErrorCode());
        return result;
    }

    /**
     * 下级平台主动关闭主从链路通知消息
     *
     * @param upCloseLinkInform
     * @return
     */
    public byte[] upCloseLinkInform(UpCloseLinkInform upCloseLinkInform) {
        return BitOperator.integerTo1Bytes(upCloseLinkInform.getReasonCode());
    }

    /**
     * 作为服务端的应答消息----------------------------------------------------------
     */

    /**
     * 从链路连接应答消息
     *
     * @param downConnectRsp
     * @return
     */
    public byte[] downConnectRsp(DownConnectRsp downConnectRsp) {
        return BitOperator.integerTo1Bytes(downConnectRsp.getResult());
    }

    /**
     * 从链路注销应答消息
     *
     * @return
     */
    public byte[] downDisconnectRsp() {
        return nullResponseBody;
    }

    /**
     * 从链路保持连接应答消息
     *
     * @return
     */
    public byte[] downLinkTestRsp() {
        return nullResponseBody;
    }

    /**
     * 数据包
     */

    /**
     * 组车辆基本信息包
     *
     * @param basicVehicleInfo
     * @return
     */
    public byte[] getBasicVehicleInfo(BasicVehicleInfo basicVehicleInfo) {
        return BitOperator.concatAll(BitOperator.padRight(BitOperator.stringToBytes(basicVehicleInfo.getVehicleNo()),21),
                BitOperator.integerTo1Bytes(basicVehicleInfo.getVehicleColor()));
    }

    /**
     * 车辆定位信息数据体数据包
     *
     * @param gnssData
     * @return
     */
    public static byte[] getGnssData(GnssData gnssData) {
        if(gnssData == null)return new byte[36];
        return BitOperator.concatAll(BitOperator.integerTo1Bytes(gnssData.getEncrypt()),
                dateTodmyy(gnssData.getDate()),
                dateTohms(gnssData.getDate()),
                BitOperator.longToBytes((long) (gnssData.getLon()*1000000), 4),
                BitOperator.longToBytes((long) (gnssData.getLat()*1000000), 4),
                BitOperator.longToBytes(gnssData.getVec1(), 2),
                BitOperator.longToBytes(gnssData.getVec2(), 2),
                BitOperator.longToBytes((long) (Math.rint(gnssData.getMileage()/100)/10), 4),
                BitOperator.integerTo2Bytes(gnssData.getDirection()),
                BitOperator.longToBytes(gnssData.getAltitude(), 2),
                BitOperator.longToBytes(gnssData.getState(),4),
                BitOperator.longToBytes(gnssData.getAlarm(), 4));
    }

    private static byte[] dateTodmyy(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return BitOperator.concatAll(
                BitOperator.integerTo1Bytes(calendar.get(Calendar.DATE)),
                BitOperator.integerTo1Bytes(calendar.get(Calendar.MONTH)+1),
                BitOperator.integerTo2Bytes(calendar.get(Calendar.YEAR)));
    }

    private static byte[] dateTohms(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return BitOperator.concatAll(
                BitOperator.integerTo1Bytes(calendar.get(Calendar.HOUR_OF_DAY)),
                BitOperator.integerTo1Bytes(calendar.get(Calendar.MINUTE)),
                BitOperator.integerTo1Bytes(calendar.get(Calendar.SECOND)));
    }

    /**
     * 子业务基本信息数据包
     */
    public byte[] getSubworkBasicInfo(int dataType, int dataLength) {
        return BitOperator.concatAll(BitOperator.integerTo2Bytes(dataType),
                BitOperator.integerTo4Bytes(dataLength));
    }

    /**
     * 获取车辆基本信息和子业务基本信息数据包
     *
     * @param basicVehicleInfo 车辆基本信息
     * @param dataType         子业务标识
     * @param dataLength       剩余业务数据长度
     * @return
     */
    public byte[] getVehicleSubworkBasicInfo(BasicVehicleInfo basicVehicleInfo, int dataType, int dataLength) {
        return BitOperator.concatAll(getBasicVehicleInfo(basicVehicleInfo),
                getSubworkBasicInfo(dataType, dataLength));
    }


    /**
     * 主链路车辆动态信息交换业务数据体组包----------------------
     */

    /**
     * 上传车辆注册信息消息
     *
     * @param upExgMsgRegister
     * @return
     */
    public byte[] upExgMsgRegister(UpExgMsgRegister upExgMsgRegister) {
        byte[] result = getVehicleSubworkBasicInfo(upExgMsgRegister.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_EXG_MSG_REGISTER, (11 + 11 + 8 + 7 + 12));
        result = BitOperator.concatAll(result,
                BitOperator.padRight(BitOperator.stringToBytes(upExgMsgRegister.getPlatformId()),11),
                BitOperator.padRight(BitOperator.stringToBytes(upExgMsgRegister.getProducerId()),11),
                BitOperator.padRight(BitOperator.stringToBytes(upExgMsgRegister.getTerminalModelType()),8),
                BitOperator.padRight(BitOperator.stringToBytes(upExgMsgRegister.getTerminalId()),7),
                BitOperator.padRight(BitOperator.stringToBytes(upExgMsgRegister.getTerminalSimCode()),12));
        return result;
    }

//    /**
//     * 实时上传车辆定位信息消息
//     *
//     * @param upExgMsgRealLocation
//     * @return
//     */
//    public byte[] upExgMsgRealLocation(UpExgMsgRealLocation upExgMsgRealLocation) {
//        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upExgMsgRealLocation.getBasicVehicleInfo(),
//                Jt809MsgIdConfig.UP_EXG_MSG_REAL_LOCATION, 36),
//                getGnssData(upExgMsgRealLocation.getGnssData()));
//    }

    /**
     * 实时上传车辆定位信息消息
     *
     * @param upExgMsgRealLocation
     * @return
     */
    public byte[] UpExgMsgRealLocation(UpExgMsgRealLocation upExgMsgRealLocation , int MsgId) {
        byte[] temp = BitOperator.concatAll(getGnssData(upExgMsgRealLocation.getGnssData()));
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upExgMsgRealLocation.getBasicVehicleInfo(), MsgId,temp.length),temp);
    }


    /**
     * 车辆定位信息自动补报请求消息
     *
     * @param upExgMsgHistoryLocation
     * @return
     */
    public byte[] UpExgMsgHistoryLocation(UpExgMsgHistoryLocation upExgMsgHistoryLocation,int msgId) {
        int gnssCnt = upExgMsgHistoryLocation.getGnssDataList().size();
        List<GnssData> gnssDataList = upExgMsgHistoryLocation.getGnssDataList();
        byte[] temp = BitOperator.concatAll(BitOperator.integerTo1Bytes(gnssCnt));
        for (GnssData gnssData : gnssDataList) {
            temp = BitOperator.concatAll(temp,getGnssData(gnssData));
        }
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upExgMsgHistoryLocation.getBasicVehicleInfo(), msgId,temp.length),temp);
    }

//    /**
//     * 车辆定位信息自动补报请求消息
//     *
//     * @param upExgMsgHistoryLocation
//     * @return
//     */
//    public byte[] upExgMsgHistoryLocation(UpExgMsgHistoryLocation upExgMsgHistoryLocation) {
//        int gnssCnt = upExgMsgHistoryLocation.getGnssDataList().size();
//        BasicVehicleInfo basicVehicleInfo = upExgMsgHistoryLocation.getBasicVehicleInfo();
//        byte[] result = getVehicleSubworkBasicInfo(basicVehicleInfo,
//                Jt809MsgIdConfig.UP_EXG_MSG_HISTORY_LOCATION, 1 + gnssCnt * 36);
//        List<GnssData> gnssDataList = upExgMsgHistoryLocation.getGnssDataList();
//        for (GnssData gnssData : gnssDataList) {
//            byte[] gnssDataByte = getGnssData(gnssData);
//            result = BitOperator.concatAll(result, gnssDataByte);
//        }
//        return result;
//    }

    /**
     * 启动车辆定位信息交换应答消息
     *
     * @param upExgMsgReturnStartupAck
     * @return
     */
    public byte[] upExgMsgReturnStartupAck(UpExgMsgReturnStartupAck upExgMsgReturnStartupAck) {
        return getVehicleSubworkBasicInfo(upExgMsgReturnStartupAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_EXG_MSG_RETURN_STARTUP_ACK, 0);
    }


    /**
     * 结束车辆定位信息交换应答消息
     *
     * @param upExgMsgReturnEndAck
     * @return
     */
    public byte[] upExgMsgReturnEndAck(UpExgMsgReturnEndAck upExgMsgReturnEndAck) {
        return getVehicleSubworkBasicInfo(upExgMsgReturnEndAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_EXG_MSG_RETURN_END_ACK, 0);
    }

    /**
     * 申请交换指定车辆定位信息请求消息
     *
     * @param upExgMsgApplyForMonitorStartup
     * @return
     */
    public byte[] upExgMsgApplyForMonitorStartup(UpExgMsgApplyForMonitorStartup upExgMsgApplyForMonitorStartup) {
        return getVehicleSubworkBasicInfo(upExgMsgApplyForMonitorStartup.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_EXG_MSG_APPLY_FOR_MONITOR_STARTUP, 16);
    }

    /**
     * 取消交换指定车辆定位信息请求消息
     *
     * @param upExgMsgApplyForMonitorEnd
     * @return
     */
    public byte[] upExgMsgApplyForMonitorEnd(UpExgMsgApplyForMonitorEnd upExgMsgApplyForMonitorEnd) {
        return getVehicleSubworkBasicInfo(upExgMsgApplyForMonitorEnd.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_EXG_MSG_APPLY_FOR_MONITOR_END, 0);
    }

    /**
     * 补发车辆定位信息请求消息
     *
     * @param upExgMsgApplyHisgnssdataReq
     * @return
     */
    public byte[] upExgMsgApplyHisgnssdataReq(UpExgMsgApplyHisgnssdataReq upExgMsgApplyHisgnssdataReq) {
        return getVehicleSubworkBasicInfo(upExgMsgApplyHisgnssdataReq.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_EXG_MSG_APPLY_HISGNSSDATA_REQ, 16);
    }

    /**
     * 上报驾驶员身份识别信息应答消息
     *
     * @param upExgMsgReportDriverInfoAck
     * @return
     */
    public byte[] upExgMsgReportDriverInfoAck(UpExgMsgReportDriverInfoAck upExgMsgReportDriverInfoAck) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upExgMsgReportDriverInfoAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_EXG_MSG_REPROT_DRIVER_INFO_ACK, (16 + 20 + 40 + 200)),
                BitOperator.stringToBytes(upExgMsgReportDriverInfoAck.getDriverName()),
                BitOperator.stringToBytes(upExgMsgReportDriverInfoAck.getDriverId()),
                BitOperator.stringToBytes(upExgMsgReportDriverInfoAck.getLicense()),
                BitOperator.stringToBytes(upExgMsgReportDriverInfoAck.getOrgName()));
    }

    /**
     * 上报车辆电子运单信息应答消息
     *
     * @param upExgMsgTakeEwaybillAck
     * @return
     */
    public byte[] upExgMsgTakeEwaybillAck(UpExgMsgTakeEwaybillAck upExgMsgTakeEwaybillAck) {
        BasicVehicleInfo basicVehicleInfo = upExgMsgTakeEwaybillAck.getBasicVehicleInfo();
        /**
         * 电子运单数据体长度
         */
        int ewayBillLength = upExgMsgTakeEwaybillAck.getEwayBillContent().length();
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(basicVehicleInfo,
                Jt809MsgIdConfig.UP_EXG_MSG_TAKE_EWAYBILL_ACK, 4 + ewayBillLength),
                BitOperator.integerTo4Bytes(ewayBillLength),
                BitOperator.stringToBytes(upExgMsgTakeEwaybillAck.getEwayBillContent()));
    }

    /**
     * 平台查岗应答消息
     *
     * @param upPlatformMsgPostQueryAck
     * @return
     */
    public byte[] upPlatformMsgPostQueryAck(UpPlatformMsgPostQueryAck upPlatformMsgPostQueryAck) {
        int infoLength = upPlatformMsgPostQueryAck.getInfoContent().length();
        byte[] result = getSubworkBasicInfo(Jt809MsgIdConfig.UP_PLATFORM_MSG_POST_QUERY_ACK, 8 + infoLength);
        return BitOperator.concatAll(result,
                BitOperator.integerTo4Bytes(upPlatformMsgPostQueryAck.getInfoId()),
                BitOperator.integerTo4Bytes(infoLength),
                BitOperator.stringToBytes(upPlatformMsgPostQueryAck.getInfoContent()));
    }

    /**
     * 下发平台间报文应答消息
     *
     * @param upPlatformMsgInfoAck
     * @return
     */
    public byte[] upPlatformMsgInfoAck(UpPlatformMsgInfoAck upPlatformMsgInfoAck) {
        return BitOperator.concatAll(getSubworkBasicInfo(Jt809MsgIdConfig.UP_PLATFORM_MSG_INFO_ACK, 8),
                BitOperator.integerTo4Bytes(upPlatformMsgInfoAck.getInfoId()));
    }

    /**
     * 车辆报警信息交互业务类
     */

    /**
     * 报警督办应答消息
     *
     * @param upWarnMsgUrgeTodoAck
     * @return
     */
    public byte[] upWarnMsgUrgeTodoAck(UpWarnMsgUrgeTodoAck upWarnMsgUrgeTodoAck) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upWarnMsgUrgeTodoAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_WARN_MSG_URGE_TODO_ACK, 5));
    }

    /**
     * 上报报警信息消息
     *
     * @param upWarnMsgAdptInfo
     * @return
     */
    public byte[] upWarnMsgAdptInfo(UpWarnMsgAdptInfo upWarnMsgAdptInfo) {
        int warnInfoLength = upWarnMsgAdptInfo.getInfoContent().length();
        if (warnInfoLength > 1024) {
            warnInfoLength = 1024;
            upWarnMsgAdptInfo.setInfoContent(upWarnMsgAdptInfo.getInfoContent().substring(0, 1024));
        }
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upWarnMsgAdptInfo.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_WARN_MSG_ADPT_INFO, (1 + 2 + 8 + 4 + 4 + warnInfoLength)),
                BitOperator.integerTo1Bytes(upWarnMsgAdptInfo.getWarnSrc()),
                BitOperator.integerTo2Bytes(upWarnMsgAdptInfo.getWarnType()),
                utcDateTo8Bytes(upWarnMsgAdptInfo.getWarnTime()),
                BitOperator.integerTo4Bytes(upWarnMsgAdptInfo.getInfoId()),
                BitOperator.integerTo4Bytes(warnInfoLength),
                BitOperator.stringToBytes(upWarnMsgAdptInfo.getInfoContent()));
    }

    /**
     * 主动上报报警信息消息（扩展）
     */
    public byte[] UpWarnMsgInfoEX(UpWarnMsgInfoEX data,int jt809MsgId){
        int warnInfoLength = BitOperator.stringToBytes(data.getInfoContent()).length;
        if (warnInfoLength > 2048) {
            warnInfoLength = 2048;
            data.setInfoContent(data.getInfoContent().substring(0, 2048));

        }
        byte[] temp = BitOperator.concatAll(BitOperator.integerTo1Bytes(data.getWarnSrc()),
                BitOperator.integerTo2Bytes(data.getWarnType()),
                utcDateTo8Bytes1(data.getWarnTime()),
                BitOperator.stringToBytes(data.getInfoId()),
                BitOperator.integerTo1Bytes(data.getDriver().length()),
                BitOperator.stringToBytes(data.getDriver()),
                BitOperator.integerTo1Bytes(data.getDriverNo().length()),
                BitOperator.stringToBytes(data.getDriverNo()),
                BitOperator.integerTo1Bytes(data.getLevel()),
                BitOperator.integerTo4Bytes((int)(data.getLon() * 1000000)),
                BitOperator.integerTo4Bytes((int)(data.getLat() * 1000000)),
                BitOperator.integerTo2Bytes(data.getAltitude()),
                BitOperator.integerTo2Bytes((int)data.getVec1()),
                BitOperator.integerTo2Bytes((int)data.getVec2()),
                BitOperator.integerTo1Bytes(data.getStatus()),
                BitOperator.integerTo2Bytes(data.getDirection()),
                BitOperator.integerTo2Bytes(warnInfoLength),
                BitOperator.stringToBytes(data.getInfoContent())
        );

        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(), jt809MsgId,temp.length),temp);
    }

    /**
     * 主动上报报警信息消息（扩展）
     */

    public byte[] upWarnMsgInfoEX(UpWarnMsgInfoEX upWarnMsgInfoEX) {
        int warnInfoLength = BitOperator.stringToBytes(upWarnMsgInfoEX.getInfoContent()).length;
        if (warnInfoLength > 2048) {
            warnInfoLength = 2048;
            upWarnMsgInfoEX.setInfoContent(upWarnMsgInfoEX.getInfoContent().substring(0, 2048));
        }
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upWarnMsgInfoEX.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_WARN_MSG_INFO_EX,
                (1 + 2 + 8 + 32 + 1 + upWarnMsgInfoEX.getDriver().length() + 1 + upWarnMsgInfoEX.getDriverNo().length() +
                        1 + 4 + 4 + 2 + 2 + 2 + 1 + 2 + 2 + warnInfoLength)),
                BitOperator.integerTo1Bytes(upWarnMsgInfoEX.getWarnSrc()),
                BitOperator.integerTo2Bytes(upWarnMsgInfoEX.getWarnType()),
                BitOperator.longToBytes(upWarnMsgInfoEX.getWarnTime()),
                BitOperator.stringToBytes(upWarnMsgInfoEX.getInfoId()),
                BitOperator.integerTo1Bytes(upWarnMsgInfoEX.getDriver().length()),
                BitOperator.stringToBytes(upWarnMsgInfoEX.getDriver()),
                BitOperator.integerTo1Bytes(upWarnMsgInfoEX.getDriverNo().length()),
                BitOperator.stringToBytes(upWarnMsgInfoEX.getDriverNo()),
                BitOperator.integerTo1Bytes(upWarnMsgInfoEX.getLevel()),
                BitOperator.integerTo4Bytes((int)(upWarnMsgInfoEX.getLon() * 1000000)),
                BitOperator.integerTo4Bytes((int)(upWarnMsgInfoEX.getLat() * 1000000)),
                BitOperator.integerTo2Bytes(upWarnMsgInfoEX.getAltitude()),
                BitOperator.integerTo2Bytes((int)upWarnMsgInfoEX.getVec1()),
                BitOperator.integerTo2Bytes((int)upWarnMsgInfoEX.getVec2()),
                BitOperator.integerTo1Bytes(upWarnMsgInfoEX.getStatus()),
                BitOperator.integerTo2Bytes(upWarnMsgInfoEX.getDirection()),
                BitOperator.integerTo2Bytes(warnInfoLength),
                BitOperator.stringToBytes(upWarnMsgInfoEX.getInfoContent())
        );
//                BitOperator.integerTo1Bytes(upWarnMsgInfoEX.getWarnSrc()),
//                BitOperator.integerTo2Bytes(upWarnMsgInfoEX.getWarnType()),
//                utcDateTo8Bytes(upWarnMsgInfoEX.getWarnTime()),
//                BitOperator.stringToBytes(upWarnMsgInfoEX.getInfoId()),
//                BitOperator.integerTo4Bytes(warnInfoLength),
//                BitOperator.stringToBytes(upWarnMsgInfoEX.getInfoContent()));
    }

    /**
     * 车辆监管业务类
     */

    /**
     * 车辆单向监听应答消息
     *
     * @param upCtrlMsgMonitorVehicleAck
     * @return
     */
    public byte[] upCtrlMsgMonitorVehicleAck(UpCtrlMsgMonitorVehicleAck upCtrlMsgMonitorVehicleAck) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upCtrlMsgMonitorVehicleAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_CTRL_MSG_MONITOR_VEHICLE_ACK, 1),
                BitOperator.integerTo1Bytes(upCtrlMsgMonitorVehicleAck.getResult()));
    }

    /**
     * 车辆拍照应答消息
     *
     * @param upCtrlMsgTakePhotoAck
     * @return
     */
    public byte[] upCtrlMsgTakePhotoAck(UpCtrlMsgTakePhotoAck upCtrlMsgTakePhotoAck) {
        int photoLen = upCtrlMsgTakePhotoAck.getPhoto().length;
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upCtrlMsgTakePhotoAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_CTRL_MSG_TAKE_PHOTO_ACK, (1 + 36 + 1 + 4 + 1 + 1 + photoLen)),
                BitOperator.integerTo1Bytes(upCtrlMsgTakePhotoAck.getPhotoRspFlag()),
                getGnssData(upCtrlMsgTakePhotoAck.getGnssData()),
                BitOperator.integerTo1Bytes(upCtrlMsgTakePhotoAck.getLensId()),
                BitOperator.integerTo4Bytes(photoLen),
                BitOperator.integerTo1Bytes(upCtrlMsgTakePhotoAck.getSizeType()),
                BitOperator.integerTo1Bytes(upCtrlMsgTakePhotoAck.getType()),
                upCtrlMsgTakePhotoAck.getPhoto());
    }

    /**
     * 下发车辆报文应答消息
     *
     * @param upCtrlMsgTextInfoAck
     * @return
     */
    public byte[] upCtrlMsgTextInfoAck(UpCtrlMsgTextInfoAck upCtrlMsgTextInfoAck) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upCtrlMsgTextInfoAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_CTRL_MSG_TEXT_INFO_ACK, 4 + 1),
                BitOperator.integerTo4Bytes(upCtrlMsgTextInfoAck.getMsgId()),
                BitOperator.integerTo1Bytes(upCtrlMsgTextInfoAck.getResult()));
    }

    /**
     * 上报车辆行驶记录应答消息
     *
     * @param upCtrlMsgTakeTravelAck
     * @return
     */
    public byte[] upCtrlMsgTakeTravelAck(UpCtrlMsgTakeTravelAck upCtrlMsgTakeTravelAck) {
        String travelDataInfo = upCtrlMsgTakeTravelAck.getTravelDataInfo();
        int travelDataInfoLen = travelDataInfo.length();
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upCtrlMsgTakeTravelAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_CTRL_MSG_TAKE_TRAVEL_ACK, 4 + travelDataInfoLen),
                BitOperator.integerTo4Bytes(travelDataInfoLen),
                BitOperator.stringToBytes(travelDataInfo));
    }

    /**
     * 车辆应急接入监管平台应答消息
     *
     * @param upCtrlMsgEmergencyMonitoringAck
     * @return
     */
    public byte[] upCtrlEmergencyMonitoringAck(UpCtrlMsgEmergencyMonitoringAck upCtrlMsgEmergencyMonitoringAck) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upCtrlMsgEmergencyMonitoringAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_CTRL_MSG_EMERGENCY_MONITORING_ACK, 1),
                BitOperator.integerTo1Bytes(upCtrlMsgEmergencyMonitoringAck.getResult()));
    }

    /**
     * 车辆静态信息交换业务类
     */

    /**
     * 补报车辆静态信息应答消息
     *
     * @param upBaseMsgVehicleAddedAck
     * @return
     */
    public byte[] upBaseMsgVehicleAddedAck(UpBaseMsgVehicleAddedAck upBaseMsgVehicleAddedAck) {
        String carInfo = upBaseMsgVehicleAddedAck.getCarInfo();
        int carInfoLen = carInfo.length();
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(upBaseMsgVehicleAddedAck.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_BASE_MSG_VEHICLE_ADDED_ACK, carInfoLen),
                BitOperator.stringToBytes(carInfo));
    }

    //******************  视频相关指令  *******************

    /**
     * 时效口令上传
     * @param data
     * @return
     */
    public byte[] upAuthorizeMsgStartup(UpAuthorizeMsgStartup data) {
        return BitOperator.concatAll(
                BitOperator.integerTo2Bytes(Jt809MsgIdConfig.UP_AUTHORIZE_MSG_STARTUP),
                BitOperator.padRight(BitOperator.stringToBytes(data.getPlantId()),11),
                BitOperator.padRight(BitOperator.stringToBytes(data.getBelongAreaAuthorizeCode()),64) ,
                BitOperator.padRight(BitOperator.stringToBytes(data.getTransAreaAuthorizeCode()), 64));
    }

    /**
     * 查询音视频资源目录应答消息
     * @param data
     * @return
     */
    public byte[] upRealVideoFileListReqAck(UpRealVideoFileListReqAck data) {
        byte[] temp = new byte[0];
        for (VideoFileInfo fileInfo: data.getVideoFileInfos()) {
            temp = BitOperator.concatAll(
                    temp,
                    BitOperator.integerTo1Bytes(fileInfo.getChannelId()),
                    utcDateTo8Bytes(fileInfo.startTime),
                    utcDateTo8Bytes(fileInfo.endTime),
                    BitOperator.hexstringToBytes(fileInfo.alarmType),
                    BitOperator.integerTo1Bytes(fileInfo.getMediaType()),
                    BitOperator.integerTo1Bytes(fileInfo.getCodeType()),
                    BitOperator.integerTo1Bytes(fileInfo.getStorageType()),
                    BitOperator.integerTo4Bytes(fileInfo.getFileSize())
            );
        }

        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_REALVIDEO_FILELIST_REQ_ACK, (5 + temp.length)),
                BitOperator.integerTo1Bytes(data.getResult()),
                BitOperator.integerTo4Bytes(data.getVideoFileInfos().size()),
                temp);
    }

    /**
     * 主动上传音视频资源目录信息消息
     * @param data
     * @return
     */
    public byte[] upFileListMsg(UpFileListMsg data) {
        byte[] temp = new byte[0];
        for (VideoFileInfo fileInfo: data.getVideoFileInfos()) {
            temp = BitOperator.concatAll(
                    temp,
                    BitOperator.integerTo1Bytes(fileInfo.getChannelId()),
                    utcDateTo8Bytes(fileInfo.startTime),
                    utcDateTo8Bytes(fileInfo.endTime),
                    BitOperator.hexstringToBytes(fileInfo.alarmType),
                    BitOperator.integerTo1Bytes(fileInfo.getMediaType()),
                    BitOperator.integerTo1Bytes(fileInfo.getCodeType()),
                    BitOperator.integerTo1Bytes(fileInfo.getStorageType()),
                    BitOperator.integerTo4Bytes(fileInfo.getFileSize())
            );
        }

        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_FILELIST_MSG, (4 + temp.length)),
                BitOperator.integerTo4Bytes(data.getVideoFileInfos().size()),
                temp);
    }

    /**
     * 远程录像回放控制应答消息
     * @param data
     * @return
     */
    public byte[] upPlayBackMsgControlAck(UpPlayBackMsgControlAck data) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_PLAYBACK_MSG_CONTROL_ACK, 1),
                BitOperator.integerTo1Bytes(data.getResult()));
    }

    /**
     * 远程录像回放请求应答消息
     * @param data
     * @return
     */
    public byte[] upPlayBackMsgStartupAck(UpPlayBackMsgStartupAck data) {

        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_PLAYBACK_MSG_STARTUP_ACK, 35),
                BitOperator.padRight(BitOperator.stringToBytes(data.getServerIp()), 32),
                BitOperator.integerTo2Bytes(data.getServerPort()),
                BitOperator.integerTo1Bytes(data.getResult())
        );
    }

    /**
     * 主动请求停止实时音视频传输应答消息
     * @param data
     * @return
     */
    public byte[] upRealVideoMsgEndAck(UpRealVideoMsgEndAck data) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_REALVIDEO_MSG_END_ACK, 1),
                BitOperator.integerTo1Bytes(data.getResult()));
    }

    /**
     * 实时音视频请求应答消息
     * @param data
     * @return
     */
    public byte[] upRealVideoMsgStartupAck(UpRealVideoMsgStartupAck data) {
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_REALVIDEO_MSG_STARTUP_ACK, 35),
                BitOperator.integerTo1Bytes(data.getResult()),
                BitOperator.padRight(BitOperator.stringToBytes(data.getServerIp()), 32) ,
                BitOperator.integerTo2Bytes(data.getServerPort())
        );
    }

    public byte[] utcDateTo8Bytes(Date date){
        return  BitOperator.concatAll(
                BitOperator.integerTo4Bytes(0),
                BitOperator.integerTo4Bytes((int)date.getTime()));
    }

    public byte[] utcDateTo8Bytes1(long timeStampms){
        String time = String.valueOf(timeStampms);
        String newTime =  time.substring(0,time.length()-3);
        long newTimeStamp = Long.valueOf(newTime);
        return  BitOperator.concatAll(
                BitOperator.integerTo4Bytes(0),
                BitOperator.integerTo4Bytes((int)newTimeStamp));
    }

    /**
     * 上报车辆审核
     * @param upBaseMsgVehicleVerify
     * @return
     */
    public byte[] upBaseMsgVehicleVerify(UpBaseMsgVehicleVerify upBaseMsgVehicleVerify) {
        byte[] content = BitOperator.stringToBytes(upBaseMsgVehicleVerify.getContent().toString());
        byte[] result = getVehicleSubworkBasicInfo(upBaseMsgVehicleVerify.getBasicVehicleInfo(),
                Jt809MsgIdConfig.UP_BASE_MSG_VEHICLE_VERIFY, content.length);
        result = BitOperator.concatAll(result,content);
        return result;
    }

    public byte[] upAlarmMediaList(UpAlarmMediaList data, int jt809MsgId) {
        byte[] temp = BitOperator.concatAll(
                BitOperator.stringToBytes(data.getInfoId()),
                BitOperator.integerTo1Bytes(data.getServer().length()),
                BitOperator.stringToBytes(data.getServer()),
                BitOperator.integerTo2Bytes(data.getPort()),
                BitOperator.integerTo1Bytes(data.getServerUserName().length()),
                BitOperator.stringToBytes(data.getServerUserName()),
                BitOperator.integerTo1Bytes(data.getPassWord().length()),
                BitOperator.stringToBytes(data.getPassWord()),
                BitOperator.integerTo1Bytes(data.getFileLists().size())
        );

        for (AlarmFileInfo fileInfo: data.getFileLists()) {
            temp = BitOperator.concatAll(
                    temp,
                    BitOperator.integerTo1Bytes(fileInfo.getFileName().length()),
                    BitOperator.stringToBytes(fileInfo.getFileName()),
                    BitOperator.integerTo1Bytes(fileInfo.getFileType()),
                    BitOperator.integerTo4Bytes(fileInfo.getFileSize()),
                    BitOperator.integerTo1Bytes(fileInfo.getFileUrl().length()),
                    BitOperator.stringToBytes(fileInfo.getFileUrl())
            );
        }
        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(),
                jt809MsgId, temp.length),
                temp);
    }

    /**
     * 主动上传终端安装信息消息
     */
    public byte[] UpExgMsgSafetyTerminal(UpExgMsgSafetyTerminal data,int jt809MsgId){
        byte[] temp = BitOperator.concatAll(BitOperator.stringToBytes(data.getTerminal_id()),
                BitOperator.stringToBytes(data.getProducer()),
                BitOperator.stringToBytes(data.getTerminal_model()),
                BitOperator.stringToBytes(data.getTerminal_id()),
                utcDateTo8Bytes(data.getInstall_time()),
                BitOperator.stringToBytes(data.getInstall_company()),
                BitOperator.stringToBytes(data.getContacts()),
                BitOperator.stringToBytes(data.getTelephone()),
                BitOperator.integerTo1Bytes(data.getCompliance_requirements()));

        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(), jt809MsgId,temp.length),temp);

    }



    /**
     * 主动上报报警处理消息（扩展）
     */
    public byte[] UpWarnMsgOperationInfoEx(UpWarnMsgOperationInfoEx data, int jt809MsgId){
        byte[] temp = BitOperator.concatAll(BitOperator.stringToBytes(data.getInfo_id()),
                BitOperator.integerTo1Bytes(data.getResult()),
                BitOperator.integerTo1Bytes(data.getMethod()),
                BitOperator.integerTo1Bytes(data.getOperator().length()),
                BitOperator.stringToBytes(data.getOperator()),
                BitOperator.integerTo1Bytes(data.getCompany().length()),
                BitOperator.stringToBytes(data.getCompany()));

        return BitOperator.concatAll(getVehicleSubworkBasicInfo(data.getBasicVehicleInfo(), jt809MsgId,temp.length),temp);
    }






}

